package cn.geminis.lowcode.processor;

import cn.geminis.lowcode.compiler.Context;
import cn.geminis.lowcode.compiler.code.LcAnnotation;
import cn.geminis.lowcode.compiler.code.LcClass;
import cn.geminis.lowcode.compiler.code.LcModifier;
import cn.geminis.lowcode.compiler.code.LcPackage;
import cn.geminis.lowcode.utils.Flags;
import cn.geminis.lowcode.utils.SourceFileContext;
import cn.geminis.lowcode.utils.Utils;
import org.springframework.util.StringUtils;

import javax.lang.model.element.Element;
import java.util.Map;
import java.util.Objects;

/**
 * @author puddi
 */
public abstract class AbstractControllerProcessor implements BaseProcessor {

    protected String entityPackageName;
    protected String parentPackageName;
    protected String controllerPackageName;
    protected String controllerName;
    protected String controllerQualifiedName;

    @Override
    public void process(Element element) {
        var createClass = false;
        entityPackageName = Utils.getElementPackageName(element);
        parentPackageName = Utils.removeLastQualifiedName(entityPackageName);
        controllerPackageName = parentPackageName + ".controller";
        controllerName = element.getSimpleName() + "Controller";
        controllerQualifiedName = controllerPackageName + "." + controllerName;

        var requestPath = (
                (
                        StringUtils.hasText(Utils.getProjectRootPackage())
                                && parentPackageName.length() > Utils.getProjectRootPackage().length()
                                && parentPackageName.startsWith(Utils.getProjectRootPackage())
                ) ?
                        parentPackageName.substring(Utils.getProjectRootPackage().length() + 1).replaceAll("\\.", "/") + "/"
                        : ""
        ) + Utils.lowerFirst(element.getSimpleName().toString());

        var existController = Context.INSTANCE.getElementUtils().getTypeElement(controllerQualifiedName);
        createClass = Objects.isNull(existController);
        LcClass controller = SourceFileContext.findClass(controllerQualifiedName);
        if (Objects.isNull(controller)) {
            if (createClass) {
                controller = new LcClass(
                        LcPackage.ensure(controllerPackageName),
                        new LcModifier(
                                Flags.PUBLIC,
                                new LcAnnotation("org.springframework.web.bind.annotation.RestController"),
                                new LcAnnotation(
                                        "org.springframework.web.bind.annotation.RequestMapping",
                                        Map.of("", requestPath)
                                ),
                                new LcAnnotation("lombok.RequiredArgsConstructor")
                        ),
                        controllerName);
            } else {
                controller = new LcClass(existController);
                controller.appendAnnotation(new LcAnnotation("org.springframework.web.bind.annotation.RestController"));
                controller.appendAnnotation(new LcAnnotation(
                        "org.springframework.web.bind.annotation.RequestMapping",
                        Map.of("", requestPath))
                );
                controller.appendAnnotation(new LcAnnotation("lombok.RequiredArgsConstructor"));
            }
            SourceFileContext.registerClass(controllerQualifiedName, controller);
        }

        this.addContent(controller, element);

        Utils.noteMessage(controllerQualifiedName + (createClass ? " Generated" : " Enhanced"));
    }

    protected abstract void addContent(LcClass controller, Element element);
}
